package com.dandelion.commons.web.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.dandelion.commons.utils.FreeMarkerUtil;
import com.dandelion.commons.web.utils.DateEditor;

import freemarker.template.Configuration;
import freemarker.template.TemplateModelException;

/**
 * 基础控制器
 * <p>User: 杨浩泉
 * <p>Date: 2015-4-22
 * <p>Version: 1.0
 */
public abstract class BaseController {
	
	protected Logger logger = LogManager.getLogger(BaseController.class);

	@Autowired
	protected FreeMarkerUtil freeMarkerUtil ;
	
	protected String viewPrefix;
    protected HttpServletRequest request ; 
    protected HttpSession session ;
	protected HttpServletResponse response ;

    /**
	 * 每次执行请求前都会先执行它再执行请求
	 * @param request
	 * @param response
	 */
	@ModelAttribute
	public void setServletApi(HttpServletRequest request, HttpServletResponse response) {
		this.request = request ;
		this.response = response ;
		this.session = request.getSession() ;
		
		//设置FreeMarker默认值，和共享变量
		try {
			Configuration configuration = freeMarkerUtil.getConfiguration() ;
			configuration.setServletContextForTemplateLoading(request.getSession().getServletContext(), "/");
			configuration.setDefaultEncoding("UTF-8");
			configuration.setSharedVariable("ctx", request.getSession().getServletContext().getContextPath());
			configuration.setSharedVariable("url", getUrl());
		} catch (TemplateModelException e) {
			e.printStackTrace();
		}
	}
	
    protected BaseController() {
        setViewPrefix(defaultViewPrefix());
    }
    
    @InitBinder
	public void initBinder(ServletRequestDataBinder binder) {
		/**
		 * 自动转换日期类型的字段格式
		 */
		binder.registerCustomEditor(Date.class, new DateEditor());
	}

    /**
     * 当前模块 视图的前缀
     * 默认
     * 1、获取当前类头上的@RequestMapping中的value作为前缀
     * 2、如果没有就使用当前模型小写的简单类名
     */
    public void setViewPrefix(String viewPrefix) {
        if (viewPrefix.startsWith("/")) {
            viewPrefix = viewPrefix.substring(1);
        }
        this.viewPrefix = viewPrefix;
    }

    public String getViewPrefix() {
        return viewPrefix;
    }

    /**
     * 获取视图名称：
     * 即prefixViewName + "/" + suffixName
     * @param suffixName
     * @return
     */
    public String viewName(String suffixName) {
        if (!suffixName.startsWith("/")) {
            suffixName = "/" + suffixName;
        }
        return getViewPrefix() + suffixName;
    }

    /**
     * 将重定向到默认getViewPrefix()
     * @param backURL
     * @return
     */
    protected String redirectToUrl(String backURL) {
        if (StringUtils.isEmpty(backURL)) {
            backURL = getViewPrefix();
        }
        if (!backURL.startsWith("/") && !backURL.startsWith("http")) {
            backURL = "/" + backURL;
        }
        return "redirect:" + backURL;
    }

    /**
     * 获取Controller注解上的路径
     * @return
     */
    protected String defaultViewPrefix() {
        String currentViewPrefix = "";
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(getClass(), RequestMapping.class);
        if (requestMapping != null && requestMapping.value().length > 0) {
            currentViewPrefix = requestMapping.value()[0];
        }
        return currentViewPrefix;
    }
    
    /**
     * 获取当前项目的绝对路径
     * @return
     */
    protected String getRealPath() {
    	return session.getServletContext().getRealPath("/") ;
    }
    
    /**
	 * 获取项目路径
	 * @param request HttpServletRequest对象
	 * @return 返回项目路径，例如：http://www.ip.com/projectName 后面没有反斜杠，后面接地址或参数必须加/
	 */
	protected String getUrl() {
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://" + request.getServerName();
		if (request.getServerPort() == 80) {
			basePath += path;
		} else {
			basePath += ":" + request.getServerPort() + path;
		}
		return basePath + "/";
	}

	/**
	 * 获取请求域名，域名不包括http请求协议头
	 * 
	 * @param request HttpServletRequest对象
	 * @return 返回域名地址
	 */
	protected String getDomain() {
		String path = request.getContextPath();
		String domain = request.getServerName();
		if (request.getServerPort() == 80) {
			domain += path;
		} else {
			domain += ":" + request.getServerPort() + path;
		}
		return domain;
	}
    
    /**
	 * 获取请求客户端ip
	 * @param request
	 * @return ip地址
	 */
	public String getRemoteAddress() {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	
	
	
	
	/**
     * 统一异常处理
     * @param e
     * @param request
     * @param response
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception e, HttpServletRequest request, HttpServletResponse response){
    	logger.error("请求发生异常：{}",e);
    	String requestType = request.getHeader("X-Requested-With");
    	
		if(!"XMLHttpRequest".equals(requestType)) {//非Ajax请求
			if(e instanceof UnauthorizedException){
	    		ModelAndView mv = new ModelAndView();
	    		//mv.addObject("error", exceptionResponse);
	    		mv.setViewName("commons/error/403");	
	    		
	    		return mv;
	    	} else {
	    		ModelAndView mv = new ModelAndView();
	    		//mv.addObject("error", exceptionResponse);
	    		mv.setViewName("commons/error/500"); 
	    		
	    		return mv;
	    	}
		} else {
			response.setCharacterEncoding("UTF-8");
			PrintWriter out = null ;
			try {
				out = response.getWriter() ;
				
				if(e instanceof UnauthorizedException){
					response.setStatus(403);
					out.print("权限不足！");
		    	} else {
		    		response.setStatus(500);
		    		out.print("请求发生异常！");
		    	}
				
			} catch (IOException ioEx) {
				ioEx.printStackTrace();
			} finally{
				out.flush();
				out.close();
			}
			return null;
		}
    }
}
